module;

export module Code_24_2_3;

template<typename... Elements>
class Typelist {};


template<typename List>
class FrontT;

template<typename Head, typename... Tail>
class FrontT<Typelist<Head, Tail...>>
{
public:
    using Type = Head;
};

template<typename List>
using Front = typename FrontT<List>::Type;

template<typename List>
class PopFrontT;

template<typename Head, typename... Tail>
class PopFrontT<Typelist<Head, Tail...>>
{
public:
    using Type = Typelist<Tail...>;
};

template<typename List>
using PopFront = typename PopFrontT<List>::Type;

template<typename List, typename NewElement>
class PushFrontT;

template<typename... Elements, typename NewElement>
class PushFrontT<Typelist<Elements...>, NewElement>
{
public:
    using Type = Typelist<NewElement, Elements...>;
};

template<typename List, typename NewElement>
using PushFront = typename PushFrontT<List, NewElement>::Type;

template<typename List>
class IsEmpty
{
public:
    static constexpr bool value = false;
};

template<>
class IsEmpty<Typelist<>>
{
public:
    static constexpr bool value = true;
};

//[1]
template<typename List, typename NewElement>
class PushBackT;
//[1]
template<typename... Elements, typename NewElement>
class PushBackT<Typelist<Elements...>, NewElement>
{
public:
    using Type = Typelist<Elements..., NewElement>;
};
//[1]
template<typename List, typename NewElement>
using PushBack = typename PushBackT<List, NewElement>::Type;

//[2]
template<typename List, typename NewElement, bool =  IsEmpty<List>::value>
class PushBackRecT;

//[2]
// recursive case:
template<typename List, typename NewElement>
class PushBackRecT<List, NewElement, false>
{
    using Head = Front<List>;
    using Tail = PopFront<List>;
    using NewTail = typename PushBackRecT<Tail, NewElement>::Type; 
public:
    using Type = PushFront<Head, NewTail>;
};

//[2]
// basis case:
template<typename List, typename NewElement>
class PushBackRecT<List, NewElement, true>
{
public:
    using Type = PushFront<List, NewElement>;
};

//[2]
// generic push-back operation:
template<typename List, typename NewElement>
class PushBackT : public PushBackRecT<List, NewElement> { };
//[2]
template<typename List, typename NewElement>
using PushBack = typename PushBackT<List, NewElement>::Type;


export
namespace Code_24_2_3 {

    void run()
    {

    }
}

